package controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;

import manager.BidMgr;
import manager.CartMgr;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import util.DateUtil;
import entity.Bid;
import entity.Course;
import entity.Section;

public class TimetableCtrl {

	public static final String PENDING_BID = "#428bca";
	public static final String SUCCESSFUL_BID = "#5cb85c";
	public static final String BOOKMARKED_BID = "#f0ad4e";
	public static final String UNSUCCESSFUL_BID = "#d9534f";

	private BidMgr bidMgr = new BidMgr();
	private CartMgr cartMgr = new CartMgr();

	private HashSet<Course> previouslyAddedCourse = new HashSet<Course>();

	public JSONArray retrieveEventsInTimetableForUserId(String userId) {

		JSONArray events = new JSONArray();
		events.addAll(constructTimetableEventsForUserId(userId));

		return events;
	}

	public ArrayList<Section> retrieveSectionsInTimetableForUserId(String userId) {

		HashSet<Section> sections = new HashSet<Section>();

		ArrayList<Bid> bids = retrieveAllBidsForStudent(userId);

		/*
		 * Add successful & pending sections.
		 */
		for (Bid eachBid : bids) {
			Section eachSection = eachBid.getSection();

			if (!eachBid.getBidResult().equals(Bid.OUT)) {
				sections.add(eachSection);
			}

		}

		/*
		 * Add bookmarked sections.
		 */
		ArrayList<Section> bookmarkedSections = retrieveBookmarkedSectionsForStudent(userId);
		sections.addAll(bookmarkedSections);

		return new ArrayList<Section>(sections);
	}

	public ArrayList<Course> retrieveCoursesInTimetableForUserId(String userId) {
		HashSet<Course> courses = new HashSet<Course>();
		ArrayList<Section> sections = retrieveSectionsInTimetableForUserId(userId);
		for (Section eachSection : sections) {
			courses.add(eachSection.getCourse());
		}
		return new ArrayList<Course>(courses);
	}

	public ArrayList<Course> retrieveSuccessfulCourses(String userId) {
		HashSet<Course> courses = new HashSet<Course>();

		ArrayList<Bid> bids = retrieveAllBidsForStudent(userId);
		ArrayList<Section> successfulSections = findSuccessfulSections(bids);
		for (Section eachSection : successfulSections) {
			courses.add(eachSection.getCourse());
		}

		return new ArrayList<Course>(courses);
	}

	public ArrayList<Course> retrievePendingCourses(String userId) {
		HashSet<Course> courses = new HashSet<Course>();

		ArrayList<Bid> bids = retrieveAllBidsForStudent(userId);
		ArrayList<Section> pendingSections = findPendingSections(bids);
		for (Section eachSection : pendingSections) {
			courses.add(eachSection.getCourse());
		}
		return new ArrayList<Course>(courses);
	}

	private ArrayList<JSONObject> constructTimetableEventsForUserId(
			String userId) {

		ArrayList<JSONObject> events = new ArrayList<JSONObject>();
		HashSet<Section> uniqueSections = new HashSet<Section>();

		ArrayList<Section> successfulSections = new ArrayList<Section>();
		ArrayList<Section> pendingSections = new ArrayList<Section>();
		ArrayList<Section> bookmarkedSections = new ArrayList<Section>();

		/*
		 * Retrieve successful & pending bids.
		 */
		ArrayList<Bid> bids = retrieveAllBidsForStudent(userId);
		for (Bid eachBid : bids) {
			Section eachSection = eachBid.getSection();

			if (eachBid.getBidResult().equals(Bid.IN)) {

				successfulSections.add(eachSection);

				// remove section from pending list if it was added there
				pendingSections.remove(eachSection);

			} else if (eachBid.getBidResult().equals(Bid.PENDING)
					&& !uniqueSections.contains(eachSection)) {

				pendingSections.add(eachSection);

			}

		}

		/*
		 * Add successful section events.
		 */
		for (Section eachSection : successfulSections) {

			Date eventStartDate = DateUtil.dateForThisWeek(eachSection
					.getDayOfWeek());
			Date eventEndDate = eachSection.getCourse().getExamStart();

			events.addAll(newRepeatingEventsForSection(eventStartDate,
					eventEndDate, eachSection, SUCCESSFUL_BID));
		}

		/*
		 * Add pending section events.
		 */
		for (Section eachSection : pendingSections) {

			uniqueSections.add(eachSection);

			Date eventStartDate = DateUtil.dateForThisWeek(eachSection
					.getDayOfWeek());
			Date eventEndDate = eachSection.getCourse().getExamStart();

			events.addAll(newRepeatingEventsForSection(eventStartDate,
					eventEndDate, eachSection, PENDING_BID));
		}

		/*
		 * Add bookmarked section events.
		 */
		bookmarkedSections = retrieveBookmarkedSectionsForStudent(userId);

		for (Section eachSection : bookmarkedSections) {

			if (!uniqueSections.contains(eachSection)) {

				uniqueSections.add(eachSection);

				Date eventStartDate = DateUtil.dateForThisWeek(eachSection
						.getDayOfWeek());
				Date eventEndDate = eachSection.getCourse().getExamStart();

				events.addAll(newRepeatingEventsForSection(eventStartDate,
						eventEndDate, eachSection, BOOKMARKED_BID));
			}

		}

		return events;
	}

	private ArrayList<JSONObject> newRepeatingEventsForSection(
			Date eventStartDate, Date eventEndDate, Section section,
			String color) {

		// Set proper section start time
		eventStartDate = DateUtil.combineDateAndTime(eventStartDate,
				section.getStartTime());

		ArrayList<JSONObject> events = new ArrayList<JSONObject>();

		DateRange eventDateRange = new DateRange(eventStartDate, eventEndDate);

		eventDateRange.setIterationField(Calendar.WEEK_OF_MONTH);

		Iterator<Date> i = eventDateRange.iterator();
		while (i.hasNext()) {
			Date eventDate = i.next();

			String id = section.getCourse().getCourseCode() + "-"
					+ section.getSectionCode();
			String title = section.getCourse().getCourseCode() + " "
					+ section.getCourse().getTitle() + " ("
					+ section.getSectionCode() + ")";
			Date eventStartTime = section.getStartTime();
			Date eventEndTime = section.getEndTime();

			JSONObject event = newEvent(id, title, eventDate, eventStartTime,
					eventEndTime, color);
			events.add(event);
		}

		/*
		 * Add exam date
		 */
		if (!previouslyAddedCourse.contains(section.getCourse())) {
			previouslyAddedCourse.add(section.getCourse());

			String id = section.getCourse().getCourseCode();
			String title = "EXAM " + section.getCourse().getCourseCode() + " "
					+ section.getCourse().getTitle();
			Date eventDate = section.getCourse().getExamStart();
			Date eventStartTime = section.getCourse().getExamStart();
			Date eventEndTime = section.getCourse().getExamEnd();

			JSONObject event = newEvent(id, title, eventDate, eventStartTime,
					eventEndTime, color);
			events.add(event);
		}

		return events;
	}

	private JSONObject newEvent(String id, String title, Date eventDate,
			Date eventStartTime, Date eventEndTime, String color) {
		JSONObject event = new JSONObject();
		event.put("id", id);
		event.put("title", title);
		String[] javascriptEventDates = newJavascriptEventDates(eventDate,
				eventStartTime, eventEndTime);
		event.put("start", javascriptEventDates[0]);
		event.put("end", javascriptEventDates[1]);
		event.put("color", color);
		event.put("allDay", false);
		return event;
	}

	private String[] newJavascriptEventDates(Date eventDate,
			Date eventStartTime, Date eventEndTime) {
		int year = DateUtil.getValueOfDateForField(eventDate, Calendar.YEAR);
		int month = DateUtil.getValueOfDateForField(eventDate, Calendar.MONTH);
		int date = DateUtil.getValueOfDateForField(eventDate, Calendar.DATE);
		int startTimeHour = DateUtil.getValueOfDateForField(eventStartTime,
				Calendar.HOUR_OF_DAY);
		int startTimeMin = DateUtil.getValueOfDateForField(eventStartTime,
				Calendar.MINUTE);
		int endTimeHour = DateUtil.getValueOfDateForField(eventEndTime,
				Calendar.HOUR_OF_DAY);
		int endTimeMin = DateUtil.getValueOfDateForField(eventEndTime,
				Calendar.MINUTE);
		String startDateStr = year + ", " + month + ", " + date + ", "
				+ startTimeHour + ", " + startTimeMin;
		String endDateStr = year + ", " + month + ", " + date + ", "
				+ endTimeHour + ", " + endTimeMin;
		return new String[] { "new Date(" + startDateStr + ")",
				"new Date(" + endDateStr + ")" };
	}

	private ArrayList<Bid> retrieveAllBidsForStudent(String userId) {
		return bidMgr.retrieveAllBidsForStudent(userId);
	}

	private ArrayList<Section> findSuccessfulSections(ArrayList<Bid> bids) {
		ArrayList<Section> sections = new ArrayList<Section>();
		for (Bid eachBid : bids) {
			if (eachBid.getBidResult().equals(Bid.IN)) {
				sections.add(eachBid.getSection());
			}
		}

		return sections;
	}

	private ArrayList<Section> findPendingSections(ArrayList<Bid> bids) {
		ArrayList<Section> sections = new ArrayList<Section>();
		for (Bid eachBid : bids) {
			if (eachBid.getBidResult().equals(Bid.PENDING)) {
				sections.add(eachBid.getSection());
			}
		}

		return sections;
	}

	private ArrayList<Section> retrieveBookmarkedSectionsForStudent(
			String userId) {
		return cartMgr.retrieveSectionsForStudent(userId);
	}

}
